package com.example.skytakeoutserver.controller.admin

import com.example.serverbase.constant.MessageConst.UPLOAD_FAILED
import com.example.serverbase.ext.Log
import com.example.skytakeoutserver.data.response.ApiResponse
import com.example.skytakeoutserver.util.AliOSSUtil
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.http.codec.multipart.FilePart
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
import java.util.*

@RestController
@RequestMapping("/admin/file")
@RequiredArgsConstructor
@Tag(name = "文件上传", description = "File to upload")
class FIleUploadController
    (
    private val aliOSSUtil: AliOSSUtil
) {
    /**
     * Post 文件上传
     * 在 Spring Boot 的 CORS 配置中，
     * 当 allowCredentials 设置为 true 时， allowedOrigins 不能包含特殊值 "*",
     * 因为浏览器不允许在 Access-Control-Allow-Origin 响应头中设置 "*", 同时还允许凭证（如 cookies）
     */
    @CrossOrigin(origins = ["*"], allowCredentials = "false")
    @PostMapping("/upload")
    fun upload(
        file: Mono<FilePart>
    ): Mono<ApiResponse<String>> {
        return file.doOnNext { part ->
            Log.info("文件上传: {}", part.filename())
        }.flatMap { part ->
            val originalFileName = part.filename()
            val extension = originalFileName.substringAfterLast('.', "")

            val objectName = UUID
                .randomUUID()
                .toString() + if (extension.isNotEmpty()) ".$extension"
            else ""

            part.content()
                .collectList()
                .map { dataBufferList ->
                    val allBytes = dataBufferList.flatMap { dataBuffer ->
                        val bytes = ByteArray(dataBuffer.readableByteCount())
                        dataBuffer.read(bytes)
                        bytes.toList()
                    }.toByteArray()

                    // 释放DataBuffer资源的操作通常是不必须的，框架自动出力
                    Log.info("Ali: " + aliOSSUtil.accessKeySecret)
                    Log.info("Ali: " + aliOSSUtil.accessKeyId)
                    Log.info("Ali: " + aliOSSUtil.bucketName)
                    Log.info("Ali: " + aliOSSUtil.endpoint)
                    // 真正上传
                    aliOSSUtil.upload(allBytes, objectName)
                }.map { filepath ->
                    ApiResponse.success(filepath)
                }.doOnError { e ->
                    Log.error("文件${originalFileName}上传失败: ${e}")
                    ApiResponse.error<String>(UPLOAD_FAILED)
                }
        }.onErrorResume { e ->
            Log.error("处理文件上传时发生错误: ${e.message}")
            Mono.just(ApiResponse.error(UPLOAD_FAILED))
        }
    }

}